package com.roy.minimq.remoting.domain.entity;

import com.roy.minimq.remoting.service.InvokeCallback;
import io.netty.channel.Channel;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 用于封装客户端的同步结果与异步结果
 */
public class ResponseFuture {

    private final Channel channel;
    // 超时时间
    private final long timeout;
    // 异步请求时的回调函数
    private final InvokeCallback invokeCallback;

    private Boolean isSendMessageOk = true;

    private volatile CountDownLatch countDownLatch = new CountDownLatch(1);

    private RemotingCommand response;

    private final AtomicBoolean executeCallbackOnlyOnce = new AtomicBoolean(false);

    public ResponseFuture(Channel channel, long timeout, InvokeCallback callback) {
        this.channel = channel;
        this.timeout = timeout;
        this.invokeCallback = callback;
    }

    //对于同步请求，使用countdownlatch阻塞，来模拟同步。
    //在等待时间内，如果请求已经返回，将会主动释放锁。

    public RemotingCommand waitResponse() throws InterruptedException {
        this.countDownLatch.await(timeout, TimeUnit.MILLISECONDS);
        return this.response;
    }

    public void putResponse(RemotingCommand response) {
        this.response = response;
        this.countDownLatch.countDown();
    }
    //通过CAS保证只执行一次。
    public void executeCallbackOnce() {
        if (null != invokeCallback) {
            executeCallbackOnlyOnce.compareAndSet(false, true);
            invokeCallback.operationComplete(this);
        }
    }

    public Channel getProcessChannel(){
        return this.channel;
    }

    public Boolean getSendMessageOk() {
        return isSendMessageOk;
    }

    public void setSendMessageOk(Boolean sendMessageOk) {
        isSendMessageOk = sendMessageOk;
    }

    @Override
    public String toString() {
        return "ResponseFuture{" +
                "isSendMessageOk=" + isSendMessageOk +
                ", response=" + response +
                '}';
    }

    public void setResponse(RemotingCommand response) {
        this.response = response;
    }

    public InvokeCallback getInvokeCallback() {
        return invokeCallback;
    }
}
